# coding=utf8
# 全世界最帅的帅哥
import json
from comment.utils.financial_redis import fr
from comment.utils.tokens_pyjwt import generate_tokens, verify_tokens
from flask_restful import Resource, reqparse
from flask import current_app, request, g
from comment.modules.user import User
from comment.modules.account import Account
from comment.utils.send_message import send_message
from .constants import SMS_CODE_EXPIRE, INVITE_MONEY, LIMIT_SMS_CODE_BY_MOBILE, LIMIT_SMS_CODE_BY_IP, MAIL_SUBJECT_TEST
from flask_restful.reqparse import RequestParser
from comment.modules import db
from comment.utils.decorators import login_required
from comment.utils.limiter import limiter
from flask_limiter.util import get_remote_address
from .serializer import InvitedListSerializer, UserInfoSerializer
from ..account.serializer import AccountInfoSerializer
from flask_mail import Message
from comment.utils.financial_mail import financial_mail


class Login(Resource):
    """
    登录的资源类
    """

    def post(self):
        rp = RequestParser()
        rp.add_argument("username", required=True)
        rp.add_argument("password", required=True)
        args = rp.parse_args()
        username = args.username
        password = args.password
        user = User.query.filter(User.username == username).first()
        if user:
            if user.check_password(password):
                # 用户登录成功，生成一个token，以便于后面去认证
                token = generate_tokens(user.id)
                # current_app.logger.info(f"用户{user.username}登录成功!")
                # current_app.logger.info(f"测试验证{token}", verify_tokens(token))
                return {"msg": "登录成功", "token": token}
            else:
                return {"message": "用户名或者密码错误!", "code": 20001}


class LoginOut(Resource):
    """
    退出登录资源类
    """

    method_decorators = [login_required]

    # method_decorators = {
    #     "post": [login_required],
    #     "get": [login_required]
    # }

    def post(self):
        # 后端只需要把全局变量中g的user_id置空
        # 要结合前端 把请求头中的token一并删除掉才能实现退出登录
        # token只要在有效期内，即使g的user_id清空，下一次访问请求的时候 又会验证成功token，再把user_id放到g中
        g.user_id = None
        return {"msg": "退出登录成功!"}


class IsExistPhone(Resource):
    """
    判断手机号是否存在
    """

    def post(self):
        # post请求往往会被封装成一个json对象
        phone = request.json.get("phone")
        user = User.query.filter(User.phone == phone).first()
        if user:
            return {"message": "此手机号已经注册过，请更换手机号", "code": 20001}
        return {"msg": "success!"}


class SmsCode(Resource):
    """
    发送手机短信，验证手机号
    """
    decorators = [
        limiter.limit(LIMIT_SMS_CODE_BY_MOBILE, key_func=lambda: request.args.get("phone"),
                      error_message="TOO MANY REQUEST"),
        limiter.limit(LIMIT_SMS_CODE_BY_IP, key_func=get_remote_address,
                      error_message="TOO MANY REQUEST")
    ]

    def get(self):
        phone = request.args.get("phone").strip()
        # 调用接口发送随机验证码
        import random
        code = str(random.randint(1000, 9999))
        # result = send_message(code)
        re_dict = {"statusCode": "000000"}
        # re_dict = json.loads(result)
        if re_dict["statusCode"] == "000000":
            current_app.logger.info(f"给手机号：{phone} 发送短信成功")
            # 验证码存到redis，还需要把验证码在注册的请求中去验证
            fr.setex(name=f"register:{phone}", time=SMS_CODE_EXPIRE, value=code)
            return {"msg": "success!", "smsCode": code}
        else:
            return {"message": f"给手机号：{phone}发送验证码失败!", "code": 20002}


class Register(Resource):
    """
    用户注册的资源类
    """

    def post(self):
        rp = RequestParser()
        rp.add_argument("phone", required=True)
        rp.add_argument("username", required=True)
        rp.add_argument("password", required=True)
        # rp.add_argument("attackPwd", required=True)
        rp.add_argument("code", required=True)
        rp.add_argument("invite_code")

        args = rp.parse_args()
        phone = args.phone
        username = args.username
        password = args.password
        # attack_pwd = args.attackPwd
        code = args.code
        invite_code = args.invite_code

        # 验证用户名是否唯一
        u = User.query.filter(User.username == username).first()
        if u:
            current_app.logger.info("用户名已经存在，请更换用户名注册")
            return {"message": "用户名重复，请直接登录或换个用户名注册", "code": 20001}

        # 从Redis数据库中获取之前保存的验证码
        real_code = fr.get(f"register:{phone}")
        real_code = real_code.decode("utf8")
        # redis中不存在验证码，说明验证码已经过期了
        if not real_code:
            current_app.logger.info("验证码过期！")
            return {"message": "验证码过期了", "code": 20001}
        # 填写的验证码与redis中的不匹配，说明输入错误
        if real_code != code:
            current_app.logger.info("验证码错误，请重新输入")
            return {"message": "验证码错误，请重新输入！"}

        # 如果能进入这行代码，说明填写的验证码成功了
        # 把用户保存到数据库中
        # 注意数据库中保存到数据库中的时候是密文，用property装饰器的方法填入数据
        u = User(username=username, phone=phone, pwd=password)

        # 保证事务的原子性用try，except结构
        try:
            if invite_code:
                self.check_invite(u, invite_code)
            db.session.add(u)
            # 把数据插入到数据库的缓冲区，并不是插入到数据库 可以得到自增的ID
            db.session.flush()
            account = Account(userId=u.id)
            db.session.add(account)
            db.session.commit()
            return {"msg": "注册成功"}
        except Exception as e:
            current_app.logger.error(e)
            db.session.rollback()
            return {"message": "用户注册时，插入数据库失败", "code": 20001}

    def check_invite(self, user, invite_code):
        invite_user_id = invite_code.strip()
        # 邀请人对象
        invite_user = User.query.filter(User.inviteId == invite_user_id).first()
        if invite_user:
            user.invite_user_id = invite_user.id
            # 邀请人代金券加50
            invite_user.accountInfo.discount += INVITE_MONEY
            # 邀请人邀请用户数量加1
            invite_user.sumFriends += 1


class UserAvatar(Resource):
    """
    管理用户的头像
    """
    # 登录拦截器
    method_decorators = [login_required]

    def post(self):
        """
        上传用户头像图片
        :return:
        """
        # 用户上传的图片数据
        img_data = request.files["file"]
        user_id = g.user_id
        user = User.query.filter(User.id == user_id).first()

        # 设置用户头像图片保存的路径
        img_dir = current_app.config["AVATAR_DIR"]
        # 设置文件名
        img_name = str(user_id) + "_" + img_data.filename
        file_path = img_dir + "\\" + img_name
        # 保存文件
        try:
            img_data.save(file_path)

            # 在数据库中保存用户头像图片的文件名
            if user:
                user.avatar = img_name
                db.session.commit()
                return {"msg": "上传头像成功", "avatar": img_name}
        except Exception as e:
            current_app.logger.error(e)
            return {"message": "头像文件上传失败！"}, 402


class InviteCode(Resource):
    """邀请码奖励的资源类"""

    method_decorators = [login_required]

    def post(self):
        # 生成邀请码
        user_id = g.user_id
        user = User.query.filter(User.id == user_id).first()
        # 根据用户名，采用uuid算法生成一个唯一的邀请码
        import uuid
        invite_code = str(uuid.uuid5(uuid.NAMESPACE_DNS, user.username))
        user.inviteId = invite_code
        db.session.commit()  # 保存到数据库中
        return {"msg": "生成邀请码成功", "invited_code": invite_code}

    def get(self):
        # 查询被邀请人的列表
        user_id = g.user_id
        # 查询被邀请的人
        invited_list = User.query.filter(User.invite_user_id == user_id).all()
        if invited_list:
            data = InvitedListSerializer(invited_list).to_dict()
            return {"msg": "success", "data": data}
        else:
            return {"msg": "暂时还没有邀请过用户哦~", "data": ""}


class UserInfo(Resource):
    # 用户信息资源类
    method_decorators = [login_required]

    def get(self):
        # 查看用户信息
        user_id = g.user_id

        user = User.query.filter(User.id == user_id).first()
        user_info_data = UserInfoSerializer(user).to_dict()
        # 查询当前用户所对应的账户信息
        account = Account.query.filter(Account.userId == user_id).first()

        account_data = {}
        if account:
            account_data = AccountInfoSerializer(account).to_dict()

        return {
            "role": ["admin"] if user.role else ["user"],
            "userInfoData": user_info_data,
            "accountInfo": account_data
        }


class EmailMessageCode(Resource):
    decorators = [
        limiter.limit(LIMIT_SMS_CODE_BY_MOBILE, key_func=lambda: request.args.get("phone"),
                      error_message="TOO MANY REQUEST"),
        limiter.limit(LIMIT_SMS_CODE_BY_IP, key_func=get_remote_address,
                      error_message="TOO MANY REQUEST")
    ]

    def get(self):
        import random
        email = request.args.get("email")
        real_code = random.randint(100000, 999999)
        message = Message(subject=MAIL_SUBJECT_TEST, recipients=[email],
                          body=f"您正在添加或者修改邮箱,验证码为{real_code}, 有效期为10分钟, 请尽快完成操作")

        financial_mail.send(message)
        fr.setex(name=f"{email}_key", time=SMS_CODE_EXPIRE, value=real_code)
        return {"msg": "发送邮箱成功"}


class EmailResource(Resource):
    method_decorators = [login_required]

    def post(self):
        rp = reqparse.RequestParser()
        rp.add_argument("email", required=True)
        rp.add_argument("code", required=True)
        args = rp.parse_args()
        email = args.email
        code = args.code
        real_code = fr.get(f"{email}_key").decode("utf8")
        if not real_code:
            return {"message": "验证码已过期"}
        if real_code != code:
            return {"message": "验证码错误，请重新输入"}
        user = User.query.filter(User.id == g.user_id).first()
        user.email = email
        db.session.commit()
        return {"msg": "上传邮箱成功！"}


class PayPassword(Resource):
    """设置支付密码"""
    method_decorators = [login_required]

    def post(self):
        rp = reqparse.RequestParser()
        rp.add_argument("pwd", required=True)
        args = rp.parse_args()
        pwd = args.pwd
        user_id = g.user_id
        user = User.query.filter(User.id == user_id).first()
        if user:
            user.pay_pwd = pwd
            user.payPwdStatus = 1
            db.session.commit()
            return {"msg": "设置支付密码成功"}
        else:
            return {"message": "server_error", "code": 20001}


class LoginPwd(Resource):
    # 修改登录密码
    method_decorators = [login_required]

    def put(self):
        rp = reqparse.RequestParser()
        rp.add_argument("orgPwd", required=True)
        rp.add_argument("newPwd", required=True)
        args = rp.parse_args()
        new_pwd = args.newPwd
        org_pwd = args.orgPwd
        user = User.query.filter(User.id == g.user_id).first()
        if user:
            if user.check_password(org_pwd):
                user.pwd = new_pwd
                db.session.commit()
                return {"msg": "修改密码成功！"}
            else:
                return {"message": "原密码错误，请重新输入！"}
        return {"message": "server_error", "code": 20001}


class RealNameAuth(Resource):
    method_decorators = [login_required]

    # 实名认证模拟
    def post(self):
        rp = RequestParser()
        rp.add_argument('realName', required=True)
        rp.add_argument('idNum', required=True)
        args = rp.parse_args()
        real_name = args.realName
        id_num = args.idNum
        user = User.query.filter(User.id == g.user_id).first()
        if user.realName:
            return {"code": 20001, 'message': '不可重复验证'}
        else:
            user.realName = real_name  # 名字
            user.realNameStatus = 1  # 实名状态
            user.idNum = id_num  # 身份证
            db.session.commit()
            return {'msg': 'success'}
